SPDX-FileCopyrightText: 2020 Christophe Demiralp & Kadir Kaya SPDX-FileCopyrightText: 2024 AlICe laboratory https://alicelab.be
SPDX-License-Identifier: GPL-3.0-or-later
Projet Divisibility I , II, III de Manfred Mohr Christophe Demiralp, Kadir Kaya
import bpy
import math
import random
from random import randint
from math import radians
from math import cos
from math import sinEffacer tout avant de relancer le code
def nettoyage():
bpy.ops.object.select_all(action="SELECT")
bpy.ops.object.delete(use_global=False)
bpy.ops.outliner.orphans_purge()
liste1 = []
liste2 = []
liste_bool_dessine = [
False,
False,
False,
False,
False,
False,
False,
False,
False,
False,
False,
False,
]Création des outils de travail en connexion avec Blender et Python
Permet de selectionner plusieurs cubes à la fois
def select_multiple(cube):Deselectionner tout les objects
bpy.ops.object.select_all(action="DESELECT")
for o in bpy.data.objects:
if o.name in (cube):
o.select_set(True)Edit mode
def Edit():
bpy.ops.object.editmode_toggle()Boolean = Division
def Boolean(un, deux):
bpy.ops.object.select_all(action="DESELECT")un = Selectionne le cube que l’on désire appliquer un Boolean
bpy.data.objects[un].select_set
bpy.ops.object.modifier_add(type="BOOLEAN")
bpy.context.object.modifiers["Boolean"].operation = "DIFFERENCE"deux = Selectionne le deuxieme cube
bpy.context.object.modifiers["Boolean"].object = bpy.data.objects[deux]
bpy.ops.object.modifier_apply(modifier="Boolean")Permet de supprimer les cubes que l’on desire
def delete_quadrants(cube1, cube2, cube3, cube4):
select_multiple([cube1, cube2, cube3, cube4])
bpy.ops.object.delete(use_global=False)Extraire les faces et épaissir les arretes
def wireframe(cube):
cube = bpy.ops.object.modifier_add(type="WIREFRAME")
bpy.context.object.modifiers["Wireframe"].thickness = 0.2Appliquer une rotation aléatoire sur les trois axes x,y,z
def Rotation_aléatoire(rot):
rot = random.uniform(0, 3.3)random.uniform = aléatoire
bpy.ops.transform.rotate(
value=-rot,
orient_matrix=(
(random.uniform(-1, 1), random.uniform(-1, 1), random.uniform(-1, 1)),
(random.uniform(-1, 1), random.uniform(-1, 1), random.uniform(-1, 1)),
(random.uniform(-1, 1), random.uniform(-1, 1), random.uniform(-1, 1)),
),
)Appliquer une rotation aléatoire sur l’axe x et l’axe y
def Rotation_xy(cube):
r = random.uniform(0, 3.3)
t = random.uniform(0, 1.7)cube = bpy.ops.transform.rotate(value=-1, orient_matrix=((0, 0, 0), (1, 1, 0), (0, 0, 0)), constraint_axis=(False,True,False))
bpy.ops.transform.rotate(
value=r,
orient_axis="Y",
orient_type="GLOBAL",
orient_matrix=((1, 0, 0), (0, 1, 0), (0, 0, 1)),
orient_matrix_type="GLOBAL",
constraint_axis=(False, True, False),
mirror=True,
use_proportional_edit=False,
proportional_edit_falloff="SMOOTH",
proportional_size=1,
use_proportional_connected=False,
use_proportional_projected=False,
)
bpy.ops.transform.rotate(
value=-t,
orient_axis="X",
orient_type="GLOBAL",
orient_matrix=((1, 0, 0), (0, 1, 0), (0, 0, 1)),
orient_matrix_type="GLOBAL",
constraint_axis=(True, False, False),
mirror=True,
use_proportional_edit=False,
proportional_edit_falloff="SMOOTH",
proportional_size=1,
use_proportional_connected=False,
use_proportional_projected=False,
)
return r, tAppliquer une rotation prècise sur l’axe ( Va nous permettre de réappliquer la rotation du cube centre prècedent)
def Rotation_centre(r, t, cube):
bpy.ops.transform.rotate(
value=r,
orient_axis="Y",
orient_type="GLOBAL",
orient_matrix=((1, 0, 0), (0, 1, 0), (0, 0, 1)),
orient_matrix_type="GLOBAL",
constraint_axis=(False, True, False),
mirror=True,
use_proportional_edit=False,
proportional_edit_falloff="SMOOTH",
proportional_size=1,
use_proportional_connected=False,
use_proportional_projected=False,
)
bpy.ops.transform.rotate(
value=-t,
orient_axis="X",
orient_type="GLOBAL",
orient_matrix=((1, 0, 0), (0, 1, 0), (0, 0, 1)),
orient_matrix_type="GLOBAL",
constraint_axis=(True, False, False),
mirror=True,
use_proportional_edit=False,
proportional_edit_falloff="SMOOTH",
proportional_size=1,
use_proportional_connected=False,
use_proportional_projected=False,
)Redefinir l’origine du cube pou rbien le positionner et appliquer une rotation avec nouvel origin
def transform_origin(cube):
bpy.ops.object.select_all(action="DESELECT")
objectToSelect = bpy.data.objects[cube]
objectToSelect.select_set(True)
bpy.context.view_layer.objects.active = objectToSelect
bpy.context.scene.tool_settings.use_transform_data_origin = True
bpy.ops.transform.translate(
value=(-1, -1, -1),
orient_type="GLOBAL",
orient_matrix=((1, 0, 0), (0, 1, 0), (0, 0, 1)),
orient_matrix_type="GLOBAL",
mirror=True,
use_proportional_edit=False,
proportional_edit_falloff="SMOOTH",
proportional_size=1,
use_proportional_connected=False,
use_proportional_projected=False,
)
bpy.context.scene.tool_settings.use_transform_data_origin = FalseRemettre l’origin qu centre pour le positionnement du cube prochain
def origin_centre(cube):
bpy.ops.object.select_all(action="DESELECT")
objectToSelect = bpy.data.objects[cube]
objectToSelect.select_set(True)
bpy.context.view_layer.objects.active = objectToSelect
bpy.ops.object.origin_set(type="ORIGIN_CENTER_OF_MASS", center="MEDIAN")Projection isométrique et trimetrique
def axoCam(projection, canon):
bpy.ops.object.camera_add()
maScene = bpy.context.scene.render
monAxoCam = bpy.context.object
monAxoCam.data.type = "ORTHO"
monAxoCam.data.ortho_scale = 25
if projection == "axonometrique":
if canon == "isometrie": # OK
monAxoCam.name = "axoIsometrie"
monAxoCam.rotation_euler = (radians(54.74), 0.0, radians(45))
monAxoCam.location = (10, 0, 10)
maScene.pixel_aspect_x = 1
if canon == "trimetrie": # OK
monAxoCam.name = "axoTrimetrie"
monAxoCam.rotation_euler = (radians(67), 0.0, radians(34))
monAxoCam.location = (20, -18, 16)
maScene.pixel_aspect_x = 1Début du projet après les outils nécessaires
Définition pour créer un cube
def cube(x, y, z, nom):
cube = bpy.ops.mesh.primitive_cube_add(size=2, location=(x, y, z), scale=(2, 2, 2))Permet de nommer les cubes dans la collection
bpy.context.object.name = nomquadrants = plans de decoupe(x,y,z)avec des cubes
def quadrants(x, y, z):
cube_b = cube(x + 1, y + 1, z + 3, "cube_b")
liste2.append(cube_b)Permet de joindre tout les cubes du quadrant et changer son origine pour les rotations
Edit()
cube_c = cube(x + 3, y + 1, z + 1, "cube_c")
liste2.append(cube_c)
cube_d = cube(x + 1, y + 3, z + 1, "cube_d")
liste2.append(cube_d)
cube_e = cube(x + 3, y + 3, z + 3, "quadrants")
liste2.append(cube_e)
Edit()
bpy.ops.object.origin_set(type="ORIGIN_CENTER_OF_MASS", center="MEDIAN")Le cube principale qui va être en continuité
def cube_centre(x, y, z):
cube_a = cube(x + 2, y + 2, z + 2, "cube_centre")Création d’une liste avec les cubes centres
liste1.append(cube_a)Reprendre notre interprétation du divisibility1
def Divisibility1(x, y, z):
quadrants(x, y, z)
cube_centre(x, y, z)
Rotation_aléatoire(cube_centre)
Boolean("cube_centre", "quadrants")
delete_quadrants("cube_b", "cube_c", "cube_d", "quadrants")Appliquer une rotation des quadrants selon la rotation du cube_a precedent
def module2(x, y, z, r_prec, t_prec, n):Création des quadrants
quadrants(x, y, z)La rotation du premier quadrant se fait aléatoirement
if n <= 0:
Rotation_aléatoire(quadrants)
else:Rotation des quadrants qui suivent se font par rapport à la rotation aléatoire du cube centre prècedent
Rotation_centre(r_prec, t_prec, quadrants)
cube_centre(x, y, z)
r, t = Rotation_xy(cube_centre)
Boolean("cube_centre", "quadrants")
delete_quadrants("cube_b", "cube_c", "cube_d", "quadrants")
return r, tOn utilise return pour reprende les données des rotations des cubes centraux pour les réutiliser sur les quadrants
Création du Divisibility2 avec continuité
def Divisibility2(x, y, z):Premier Division sans les rotations des quadrants (On reprend DivisibilityI pour créer le Divisibility2)
Divisibility1(-1, -1, -1)
r_prec = 0
t_prec = 0Boucle avec continuité: les quadrants du deuxième cube reprend la rotation du premier cube centre. Cela permet de diviser le deuxieme cube par rapport au premier.
for n in range(0, 2, 1):
r_prec, t_prec = module2(x + n, y + n, z + n, r_prec, t_prec, n)Début de Divisibility3 Le principe est de reprendre Divisibility2 pour créer le Divisibility3. Le Divisibility2 devient alors des arrêtes du cubes 10 x 10
def dessiner_arrete(num_arrete, x, y, z, r_prec, t_prec):Chaques Divisibility2 créent une des arrêtes du cube 10 x 10 (12 arrêtes au total)
if num_arrete == 0:
for n in range(0, 4, 1):V1 (nom de l’arrete = voir image)
r_prec, t_prec = module2(x, y, z + 6 - 1.5 * n, r_prec, t_prec, n)
elif num_arrete == 1:
for n in range(0, 4, 1):V2
r_prec, t_prec = module2(x + 6, y, z + 6 - 1.5 * n, r_prec, t_prec, n)
elif num_arrete == 2:
for n in range(0, 4, 1):V3
r_prec, t_prec = module2(x + 6, y + 6, z + 1.5 * n, r_prec, t_prec, n)
elif num_arrete == 3:
for n in range(0, 4, 1):V4
r_prec, t_prec = module2(x, y + 6, z + 6 - 1.5 * n, r_prec, t_prec, n)
elif num_arrete == 4:
for n in range(0, 4, 1):H1
r_prec, t_prec = module2(x + 1.5 * n, y, z, r_prec, t_prec, n)
elif num_arrete == 5:
for n in range(0, 4, 1):H2
r_prec, t_prec = module2(x + 6, y + 1.5 * n, z, r_prec, t_prec, n)
elif num_arrete == 6:
for n in range(0, 4, 1):H3
r_prec, t_prec = module2(x + 1.5 * n, y + 6, z, r_prec, t_prec, n)
elif num_arrete == 7:
for n in range(0, 4, 1):H4
r_prec, t_prec = module2(x, y + 1.5 * n, z, r_prec, t_prec, n)
elif num_arrete == 8:
for n in range(0, 4, 1):H5
r_prec, t_prec = module2(x + 1.5 * n, y, z + 6, r_prec, t_prec, n)
elif num_arrete == 9:
for n in range(0, 4, 1):H6
r_prec, t_prec = module2(x + 6, y + 1.5 * n, z + 6, r_prec, t_prec, n)
elif num_arrete == 10:
for n in range(0, 4, 1):H7
r_prec, t_prec = module2(x + 6 - 1.5 * n, y + 6, z + 6, r_prec, t_prec, n)
elif num_arrete == 11:
for n in range(0, 4, 1):H8
r_prec, t_prec = module2(x, y + 1.5 * n, z + 6, r_prec, t_prec, n)Lorsque l’une des arrêtes est génerer, on le prècise avec True dans la liste bool_dessine crée au début du code
liste_bool_dessine[num_arrete] = TrueCréation de Divisibility 3
def Divisibility3(x, y, z):On a déterminer tout les mouvemments possibles entre les arrêtes et en créer une liste Chaque arrête est en connection avec 4 autres arrêtes Cela nous permet de créer une continuité entre les arrétes générer.
liste_mouv_possible_V1 = [4, 7, 8, 11]
liste_mouv_possible_V2 = [4, 5, 8, 9]
liste_mouv_possible_V3 = [5, 6, 9, 10]
liste_mouv_possible_V4 = [6, 7, 10, 11]
liste_mouv_possible_H1 = [0, 1, 5, 7]
liste_mouv_possible_H2 = [1, 2, 4, 6]
liste_mouv_possible_H3 = [2, 3, 5, 7]
liste_mouv_possible_H4 = [0, 3, 4, 6]
liste_mouv_possible_H5 = [0, 1, 9, 11]
liste_mouv_possible_H6 = [1, 2, 8, 10]
liste_mouv_possible_H7 = [2, 3, 9, 11]
liste_mouv_possible_H8 = [0, 3, 8, 10]Réunir tout les mouvements dans une liste
listes_mouv_possibles = [
liste_mouv_possible_V1,
liste_mouv_possible_V2,
liste_mouv_possible_V3,
liste_mouv_possible_V4,
liste_mouv_possible_H1,
liste_mouv_possible_H2,
liste_mouv_possible_H3,
liste_mouv_possible_H4,
liste_mouv_possible_H5,
liste_mouv_possible_H6,
liste_mouv_possible_H7,
liste_mouv_possible_H8,
]
r_prec = 0
t_prec = 0Boucle qui crée 6 arrêtes en connexion
for etape in range(0, 6, 1):Selection de la première arrëte aléatoirement
if etape == 0:
arrete_actuel = randint(0, 11)Création des 5 arrëtes suivants en connexion
else:Création d’une liste qui stock tout les ‘False’, c4est a dire les arrêtes qui ne sont pas encore selectionné dans la boucle
liste_disponibles = []i = selectionne sur ’ possibilités les qrrêtes qui ne sont pas encore selectionnées
for i in range(0, 3, 1):Si dans la liste_bool_dessine(créer tout au début du code), les arrêtes ne sont pas encore génerées, on le stock dqns une nouvelle liste (liste_disponibles)
if liste_bool_dessine[listes_mouv_possibles[arrete_actuel][i]] == False:
liste_disponibles.append(listes_mouv_possibles[arrete_actuel][i])l’arrête_actuel générée va alors prendre un chemin aléatoire mais en connexion avec l’arrête prècédent De plus, il ne générera pas une arrête déjà créé dqns lq boucle.
arrete_actuel = liste_disponibles[randint(0, len(liste_disponibles) - 1)]Execution de la définition par rapport à l’arrête prècedent
dessiner_arrete(arrete_actuel, x, y, z, r_prec, t_prec)Execution du programme :
nettoyage()Différentes étapes de l’oeuvre:
quadrants(0,0,0) cube_centre(0,0,0) Divisibility1(0,0,0) Divisibility2(0,0,0)
Divisibility3(0, 0, 0)Imprimer les listes:
print(liste1)
print(liste2)Choisir l’angle de la caméra:
axoCam (‘axonometrique’,’isometrie’)
axoCam("axonometrique", "trimetrie")